from myelin.rdf.bindery.Conversions import ToStatements

from myelin.server.core.ft import ModelDriver
from myelin.rdf.Ns import RDFS_SEEALSO, RDFS_LABEL
from myelin.rdf.bindery.Model import OBJECT_TYPE_RESOURCE, OBJECT_TYPE_LITERAL

from myelin.Ns import MYELIN, DC, DCTERMS, DCMITYPE
from myelin.rdf.Ns import RDF_TYPE, RDFS_SEEALSO

from nodetypes import config
from nodetypes.formats.Document import Document
from nodetypes.ntypes import Action
from nodetypes.Ns import GRAPHS_NS

import Serializers


class Document(Document):
    
    serializers = Serializers.SERIALIZERS
    defaultSerializer = Serializers.SERIALIZERS[config.DEFAULT_RDF_GRAPH_METHOD]
    
    newAgentDriver = staticmethod(ModelDriver.FromRepo)
    newProfilesDriver = staticmethod(ModelDriver.FromRepo)
    
    convertToStatements = staticmethod(ToStatements)
    baseServiceType = Action.ViewService
    
    defaultNsMap = config.DEFAULT_NSMAP
    
    def createDocument(self, context, source):
        s = self.serializers.get(
            context.method,
            self.defaultSerializer
        ).FromTuples(
            self.createStatements(
                context,
                set().update
            ).__self__
        )
        
        doc, imt = s.serialize(
            None,  
            context.server.namespaceMap or self.defaultNsMap,
            context.preferredEncoding
        )
        
        if isinstance(doc,str):
            return doc, self.getImt(
                context,
                s.method,
                imt,
                context.preferredEncoding
            )
        
        return doc, self.getImt(
            context,
            s.method,
            imt
        )
    
    def createStatements(self, context, consumer):
        request = context.request
        mid = context.account
        if mid.isAgent():
            consumer((
                (
                    u'',
                    MYELIN + u'requestor',
                    mid.agentId,
                    None,
                    None,
                    OBJECT_TYPE_RESOURCE
                ),
            ))
            
        action = context.action
        actionType = context.nodeType.actions[action]
        typeInfo = context.nodeType.typeInfo
        
        mode = context.mode
        
        DC_SOURCE = DC + u'source'        
        DC_TYPE = DC + u'type'
        DCMITYPE_SERVICE = DCMITYPE + u'Service'
        mid = context.model.rdf_value
        newUri = self.newUri
        
        consumer((
            (
                u'',
                DC_TYPE,
                DCMITYPE_SERVICE,
                None,
                u'',
                OBJECT_TYPE_RESOURCE
            ), (
                u'',
                MYELIN + u'service-handler',
                self.newServiceHandlerUri(
                    action,                    
                    typeInfo['name'],
                    typeInfo['namespace-uri']
                ),
                None,
                u'',
                OBJECT_TYPE_RESOURCE
            ), (
                u'',
                DC + u'publisher',
                context.defaults.domain_uri,
                None,
                u'',
                OBJECT_TYPE_RESOURCE
            ), (            
                u'',
                DC_SOURCE,
                unicode(mid),
                None,
                u'',
                OBJECT_TYPE_RESOURCE
            ), (
                u'',
                DCTERMS + u'created',
                self.newDateTimeString(
                    context.session.dateTime
                ),
                None,
                u'',
                OBJECT_TYPE_LITERAL
            ), (
                u'',
                DC + u'identifier',
                newUri(),
                None,
                u'',
                OBJECT_TYPE_LITERAL
            ), (
                u'',
                MYELIN + u'graph-uri',
                unicode(request.graphs[context.mode].uri),
                None,
                u'',
                OBJECT_TYPE_RESOURCE
            ), (
                u'',
                MYELIN + u'action',
                unicode(action),
                None,
                u'',
                OBJECT_TYPE_LITERAL
            ), (
                u'',
                MYELIN + u'mode',
                unicode(mode),
                None,
                u'',
                OBJECT_TYPE_LITERAL
            ), 
        ))
        consumer(
            (
                u'',
                RDF_TYPE,
                unicode(t),
                None,
                u'',
                OBJECT_TYPE_RESOURCE
            ) for t in actionType.classTypes
        )
                
        urlFormatter = context.urlFormatter.formatUrl        
        method = context.method
        
        ep = getattr(context.defaults,'sparql_endpoint',None)
        if ep:
            consumer((
                (
                    u'',
                    MYELIN + u'sparql-endpoint',
                    urlFormatter(ep,method=method),
                    None,
                    u'',
                    OBJECT_TYPE_RESOURCE
                ),
            ))
            
        ep = getattr(context.defaults,'versa_endpoint',None)
        if ep:
            consumer((
                (
                    u'',
                    MYELIN + u'versa-endpoint',
                    urlFormatter(ep,method=method),
                    None,
                    u'',
                    OBJECT_TYPE_RESOURCE
                ),
            ))
            
        ep = getattr(context.defaults,'keyword_search_endpoint',None)
        if ep:
            consumer((
                (
                    u'',
                    MYELIN + u'keyword-search-endpoint',
                    urlFormatter(ep,method=method),
                    None,
                    u'',
                    OBJECT_TYPE_RESOURCE
                ),
            ))
        #model.rdf_prefetch()
       
        baseUrl = context.uriMapper.apply(context.sourceUri)
        map = self.extensionsMap.get
        DC_REL = DC + 'relation'
        DC_FORMAT = DC + 'format'
        for m in context.methods.keys():
            if not m:
                continue
            if m != method:
                uri = urlFormatter(baseUrl, method=m)                
                m = map(m)
                if m:
                    consumer((
                        (
                            uri,
                            DC_FORMAT,
                            unicode(m.imt),
                            None,
                            u'',
                            OBJECT_TYPE_LITERAL
                        ), (
                            uri,
                            DC_SOURCE,
                            mid,
                            None,
                            u'',
                            OBJECT_TYPE_RESOURCE
                        ), (
                            u'',
                            RDFS_SEEALSO,
                            uri,
                            None,
                            u'',
                            OBJECT_TYPE_RESOURCE
                        ), 
                    ))
                else:
                    consumer((
                        (
                            u'',
                            RDFS_SEEALSO,
                            uri,
                            None,
                            u'',
                            OBJECT_TYPE_RESOURCE
                        ), 
                    ))
                    
                consumer(
                    (
                        uri,
                        RDF_TYPE,
                        unicode(t),
                        None,
                        u'',
                        OBJECT_TYPE_RESOURCE
                    ) for t in actionType.classTypes
                )
        
        m = map(method)
        if m:
            imt = m.imt
            typ = m.classTypes and m.classTypes[0] or MYELIN + u'MachineMetadataAdaptation'
        else:
            imt = u'text/rdf+xml'
            typ = MYELIN + u'MachineMetadataAdaptation'
                
        for m,g in request.graphs.items():
            if m != mode:
                uri = urlFormatter(baseUrl, mode=m)  
                consumer((
                    (
                        u'',
                        RDFS_SEEALSO,
                        uri,
                        None,
                        u'',
                        OBJECT_TYPE_RESOURCE
                    ), (
                        uri,
                        DC_FORMAT,
                        imt,
                        None,
                        u'',
                        OBJECT_TYPE_LITERAL
                    ), (
                        uri,
                        DC_SOURCE,
                        mid,
                        None,
                        u'',
                        OBJECT_TYPE_RESOURCE
                    ), (
                        uri,
                        MYELIN + u'mode',
                        unicode(m),
                        None,
                        u'',
                        OBJECT_TYPE_LITERAL
                    ), (
                        uri,
                        DC_TYPE,
                        DCMITYPE_SERVICE,
                        None,
                        u'',
                        OBJECT_TYPE_RESOURCE
                    ),
                ))
                consumer(
                    (
                        uri,
                        RDF_TYPE,
                        t,
                        None,
                        u'',
                        OBJECT_TYPE_RESOURCE
                    ) for t in actionType.classTypes
                )
                    
                
        action = context.action
        imt = map(method)
        imt = imt and imt.imt or method
        for a,t in context.nodeType.actions.items():
            if a == action or not isinstance(t, self.baseServiceType):
                continue
            if method in t:
                uri = urlFormatter(baseUrl, action=a, method=method)
                
                consumer((
                    (
                        u'',
                        RDFS_SEEALSO,
                        uri,
                        None,
                        u'',
                        OBJECT_TYPE_RESOURCE
                    ), (
                        uri,
                        DC_FORMAT,
                        imt,
                        None,
                        u'',
                        OBJECT_TYPE_LITERAL
                    ), (
                            uri,
                            DC_SOURCE,
                            mid,
                            None,
                            u'',
                            OBJECT_TYPE_RESOURCE
                    ), (
                            uri,
                            MYELIN + u'action',
                            unicode(a),
                            None,
                            u'',
                            OBJECT_TYPE_LITERAL
                    ),
                ))
                consumer(
                    (
                        uri,
                        RDF_TYPE,
                        c,
                        None,
                        u'',
                        OBJECT_TYPE_RESOURCE
                    ) for c in t.classTypes
                )
                
        return self.getStatements(context, consumer)     
    
    def getStatements(self, context, consumer): 
        consumer(context.model.rdf_getStatements())
        return consumer
    
    def getAgentStatements(self, context, consumer, model, locale):
        
        models = context.server.graphs
        href = models[GRAPHS_NS + 'agents'].get('public')
        if href:
            mrs = model.rdf_clone(
                model.Initialize(
                    self.newAgentDriver(
                        context.repo,
                        href
                    )
                )
            ).rdf_toStatements
        else:
            mrs = model.rdf_toStatements
            
        consumer(mrs('rdfType'))
        consumer(mrs('foafNick'))
        consumer(mrs('foafName'))
        consumer(mrs('foafMbox_sha'))
        consumer(mrs('foafHomepage'))        
            
        href = context.urlFormatter.newUrlMapper(
            True,
            action='view',
            mode='published'
        )
        def _filter(m):
            for np,n in m:
                #print "profile: %s" % p.rdf_value
                seeAlso = href(n.rdf_getDomain())
                if seeAlso and \
                    locale in n.dcLanguage:
                    nrs = n.rdf_toStatements
                    
                    consumer(nrs('rdfType'))
                    consumer(nrs('dcTitle'))
                    consumer(nrs('foafPrimaryTopic'))                    
                    
                    consumer((
                        (
                            n.rdf_value,
                            RDFS_SEEALSO,
                            seeAlso,
                            '',
                            n.rdf_domain,
                            OBJECT_TYPE_RESOURCE,
                        ),
                    ))
                                        
                    return np, n
                else:
                    tp, t = _filter(
                        n.rdf_toRelations('mTranslation')
                    )
                    if t:
                        consumer((
                            t.rdf_asStatement(
                                tp,
                                n.rdf_value                            
                            ),
                        ))
                        return np, n
            return None,None
        
        #print "profile all: %s" % str(model.rdf_join('mProfile',u' '))
        driver = models[GRAPHS_NS + 'profiles'].get('published')
        if driver:
            model = model.rdf_clone(
                model.rdf_initDriver(
                    self.newProfilesDriver(
                        context.repo,
                        driver
                    )
                )
            )
                
        np, n = _filter(
            model.rdf_toRelations('mProfile')
        )
        if n:            
            consumer((
                n.rdf_asStatement(
                    np,
                    model.rdf_value
                ),
            ))
            
        return consumer
    
# cleanup
del Serializers, \
    ModelDriver, \
    ToStatements, \
    Action